/*
 * Copyright (c) 2022 PATEO CONNECT+ (Nanjing) Co., Ltd.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include "voice_assistant_ability_proxy.h"
#include "voice_assistant_client_callback_stub.h"
#include "voice_assistant_log.h"
#include "common_utils.h"
#include <nlohmann/json.hpp>

using namespace OHOS::CarVoiceAssistant::CommonUtils;

namespace OHOS {
namespace CarVoiceAssistant {

#define WRITE_PARCEL_WITH_RET(parcel, type, data, retval)                        \
    do {                                                                         \
        if (!(parcel).Write##type(data)) {                                       \
            VOICE_ASSISTANT_LOGI("%{public}s write " #data " failed", __func__); \
            return (retval);                                                     \
        }                                                                        \
    } while (0)

#define READ_PARCEL_WITH_RET(parcel, type, out, retval)                        \
    do {                                                                       \
        if (!(parcel).Read##type(out)) {                                       \
            VOICE_ASSISTANT_LOGI("%{public}s read " #out " failed", __func__); \
            return (retval);                                                   \
        }                                                                      \
    } while (0)

    VoiceAssistantAbilityAgentProxy::VoiceAssistantAbilityAgentProxy(const sptr<IRemoteObject>& object)
        : IRemoteProxy<IVoiceAssistantAbilityAgent>(object)
    {
    }

    int32_t VoiceAssistantAbilityAgentProxy::IsEnableWakeUp(bool& isEnable)
    {
        VOICE_ASSISTANT_LOGI("IsEnableWakeUp");
        MessageParcel data;
        MessageParcel reply;

        CommonUtils::VoiceAssistantErrorCode code = DoDispatch(VOICE_ASSITANT_CMD_IS_ENABLE_WAKEUP, data, reply);
        if (code != VOICE_ASSISTANT_OK) {
            VOICE_ASSISTANT_LOGI("IsEnableWakeUp failed");
            return code;
        }

        READ_PARCEL_WITH_RET(reply, Bool, isEnable, VOICE_ASSISTANT_ERR);
        return VOICE_ASSISTANT_OK;
    }

    int32_t VoiceAssistantAbilityAgentProxy::EnableWakeUp()
    {
        VOICE_ASSISTANT_LOGI("EnableWakeUp");
        MessageParcel data;
        MessageParcel reply;

        CommonUtils::VoiceAssistantErrorCode code = DoDispatch(VOICE_ASSITANT_CMD_ENABLE_WAKEUP, data, reply);
        if (code != VOICE_ASSISTANT_OK) {
            VOICE_ASSISTANT_LOGI("EnableWakeUp failed");
            return code;
        }

        return VOICE_ASSISTANT_OK;
    }

    int32_t VoiceAssistantAbilityAgentProxy::DisableWakeUp()
    {
        VOICE_ASSISTANT_LOGI("DisableWakeUp");
        MessageParcel data;
        MessageParcel reply;

        CommonUtils::VoiceAssistantErrorCode code = DoDispatch(VOICE_ASSITANT_CMD_DISABLE_WAKEUP, data, reply);
        if (code != VOICE_ASSISTANT_OK) {
            VOICE_ASSISTANT_LOGI("DisableWakeUp failed");
            return code;
        }

        return VOICE_ASSISTANT_OK;
    }

    int32_t VoiceAssistantAbilityAgentProxy::IsRecognizing(bool& isRecognizing)
    {
        VOICE_ASSISTANT_LOGI("IsRecognizing");
        MessageParcel data;
        MessageParcel reply;

        CommonUtils::VoiceAssistantErrorCode code = DoDispatch(VOICE_ASSITANT_CMD_IS_RECOGNIZING, data, reply);
        if (code != VOICE_ASSISTANT_OK) {
            VOICE_ASSISTANT_LOGI("IsRecognizing failed");
            return code;
        }

        READ_PARCEL_WITH_RET(reply, Bool, isRecognizing, VOICE_ASSISTANT_ERR);

        return VOICE_ASSISTANT_OK;
    }

    int32_t VoiceAssistantAbilityAgentProxy::StartRecognize(CommonUtils::VoiceAssistantErrorCode& result)
    {
        VOICE_ASSISTANT_LOGI("StartRecognize");
        MessageParcel data;
        MessageParcel reply;

        CommonUtils::VoiceAssistantErrorCode code = DoDispatch(VOICE_ASSITANT_CMD_START_RECOGNIZE, data, reply);
        if (code != VOICE_ASSISTANT_OK) {
            VOICE_ASSISTANT_LOGI("StartRecognize failed");
            return code;
        }
        
        int32_t rst = VOICE_ASSISTANT_ERR;
        READ_PARCEL_WITH_RET(reply, Int32, rst, VOICE_ASSISTANT_ERR);
        result = static_cast<CommonUtils::VoiceAssistantErrorCode>(rst);

        return VOICE_ASSISTANT_OK;
    }

    int32_t VoiceAssistantAbilityAgentProxy::StopRecognize()
    {
        VOICE_ASSISTANT_LOGI("StopRecognize");
        MessageParcel data;
        MessageParcel reply;

        CommonUtils::VoiceAssistantErrorCode code = DoDispatch(VOICE_ASSITANT_CMD_STOP_RECOGNIZE, data, reply);
        if (code != VOICE_ASSISTANT_OK) {
            VOICE_ASSISTANT_LOGI("StopRecognize failed");
            return code;
        }

        return VOICE_ASSISTANT_OK;
    }

    int32_t VoiceAssistantAbilityAgentProxy::PlayTTS(CommonUtils::VoiceAssistantErrorCode& result, std::string& tts)
    {
        VOICE_ASSISTANT_LOGI("PlayTTS");
        MessageParcel data;
        MessageParcel reply;

        WRITE_PARCEL_WITH_RET(data, String, tts, VOICE_ASSISTANT_ERR);

        CommonUtils::VoiceAssistantErrorCode code = DoDispatch(VOICE_ASSITANT_CMD_PLAY_TTS, data, reply);
        if (code != VOICE_ASSISTANT_OK) {
            VOICE_ASSISTANT_LOGI("PlayTTS failed");
            return code;
        }

        int32_t rst = VOICE_ASSISTANT_ERR;
        READ_PARCEL_WITH_RET(reply, Int32, rst, VOICE_ASSISTANT_ERR);
        result = static_cast<CommonUtils::VoiceAssistantErrorCode>(rst);

        return VOICE_ASSISTANT_OK;
    }

    int32_t VoiceAssistantAbilityAgentProxy::StopPlayTTS()
    {
        VOICE_ASSISTANT_LOGI("StopPlayTTS");
        MessageParcel data;
        MessageParcel reply;

        CommonUtils::VoiceAssistantErrorCode code = DoDispatch(VOICE_ASSITANT_CMD_STOP_PLAY_TTS, data, reply);
        if (code != VOICE_ASSISTANT_OK) {
            VOICE_ASSISTANT_LOGI("StopPlayTTS failed");
            return code;
        }

        return VOICE_ASSISTANT_OK;
    }

    int32_t VoiceAssistantAbilityAgentProxy::RegisterHotwords(std::string& hotwords)
    {
        VOICE_ASSISTANT_LOGI("RegisterHotwords");
        MessageParcel data;
        MessageParcel reply;

        WRITE_PARCEL_WITH_RET(data, String, hotwords, VOICE_ASSISTANT_ERR);

        CommonUtils::VoiceAssistantErrorCode code = DoDispatch(VOICE_ASSITANT_CMD_REGISTER_HOTWORDS, data, reply);
        if (code != VOICE_ASSISTANT_OK) {
            VOICE_ASSISTANT_LOGI("RegisterHotwords failed");
            return code;
        }

        return VOICE_ASSISTANT_OK;
    }

    int32_t VoiceAssistantAbilityAgentProxy::SetCoord(double latitude, double longitude)
    {
        VOICE_ASSISTANT_LOGI("SetCoord");
        MessageParcel data;
        MessageParcel reply;

        WRITE_PARCEL_WITH_RET(data, Double, latitude, VOICE_ASSISTANT_ERR);
        WRITE_PARCEL_WITH_RET(data, Double, longitude, VOICE_ASSISTANT_ERR);

        CommonUtils::VoiceAssistantErrorCode code = DoDispatch(VOICE_ASSISTANT_CMD_SET_COORD, data, reply);
        if (code != VOICE_ASSISTANT_OK) {
            VOICE_ASSISTANT_LOGI("SetCoord failed");
            return code;
        }

        return VOICE_ASSISTANT_OK;
    }

    int32_t VoiceAssistantAbilityAgentProxy::RegisterCallback()
    {
        VOICE_ASSISTANT_LOGI("RegisterCallback");
        MessageParcel data;
        MessageParcel reply;

        sptr<IVoiceAssistantClientCallback> callback = new VoiceAssistantClientCallbackStub();
        sptr<IRemoteObject> remoteObject = callback->AsObject();
        WRITE_PARCEL_WITH_RET(data, RemoteObject, remoteObject, VOICE_ASSISTANT_ERR);

        CommonUtils::VoiceAssistantErrorCode code = DoDispatch(VOICE_ASSITANT_CMD_REGISTER_CALLBACK, data, reply);
        if (code != VOICE_ASSISTANT_OK) {
            VOICE_ASSISTANT_LOGI("RegisterCallback failed");
            return code;
        }

        return VOICE_ASSISTANT_OK;
    }

    int32_t VoiceAssistantAbilityAgentProxy::ChangeSpeakerType(std::string speaker)
    {
        VOICE_ASSISTANT_LOGI("ChangeSpeakerType");
        MessageParcel data;
        MessageParcel reply;

        WRITE_PARCEL_WITH_RET(data, String, speaker, VOICE_ASSISTANT_ERR);

        CommonUtils::VoiceAssistantErrorCode code = DoDispatch(VOICE_ASSITANT_CMD_CHANGE_SPEAKER_TYPE, data, reply);
        if (code != VOICE_ASSISTANT_OK) {
            VOICE_ASSISTANT_LOGI("ChangeSpeakerType failed");
            return code;
        }

        return VOICE_ASSISTANT_OK;
    }

    CommonUtils::VoiceAssistantErrorCode VoiceAssistantAbilityAgentProxy::DoDispatch(uint32_t cmd, MessageParcel& data, MessageParcel& reply)
    {
        VOICE_ASSISTANT_LOGI("%{public}s:%{public}d cmd:%{public}d", __func__, __LINE__, cmd);

        MessageOption option;
        auto ret = Remote()->SendRequest(cmd, data, reply, option);
        VOICE_ASSISTANT_LOGI("%{public}s:%{public}d SendRequest end cmd:%{public}d ", __func__, __LINE__, cmd);
        if (ret != ERR_NONE) {
            VOICE_ASSISTANT_LOGI("failed to send request, cmd: %{public}d, ret: %{public}d", cmd, ret);
            return VOICE_ASSISTANT_ERR;
        }
        VOICE_ASSISTANT_LOGI(" success to dispatch cmd: %{public}d", cmd);
        return VOICE_ASSISTANT_OK;
    }

}
}
